using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace TestCases.Utils
{
    public static class ObjectUtils
    {

        public const string NullString = "null";
        
        public static IDictionary<string, object> ToDictionary(this object obj, IDictionary<string, object> dictionary)
        {
            if (obj == null)
            {
                return dictionary;
            }
            
            foreach (var info in obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                dictionary.Add(info.Name, info.GetValue(obj, null));
            }
            return dictionary;
        }
        
        public static IDictionary<string, object> ToDictionary(this object obj)
        {
            return obj.ToDictionary(new Dictionary<string, object>());
        }

        public static string ToSafeString(this object obj)
        {
            return (obj != null) ? obj.ToString() : NullString;
        }

        public static string ToValueString(this object obj)
        {
            if (obj == null)
            {
                return NullString;
            }            
            if (obj is Type)
            {
                return ((Type) obj).ToTypeString();
            }
            if (obj is Array)
            {
                return ((Array) obj).ToArrayString();
            }            
            if (obj is char)
            {
                return "\'" + obj + "\'";
            }
            if (obj is string || obj is StringBuilder)
            {                
                return "\"" + obj + "\"";
            }
            return obj.ToString();
        }

        public static string ToValuesString(this object[] objs)
        {
            return string.Join(", ", Array.ConvertAll<object, string>(objs, ToValueString));
        }
        
        public static string ToArrayString(this Array array)
        {
            var builder = new StringBuilder();
            var indexes = new long[array.Rank];
            ToArrayStringImpl(array, builder, indexes, 0);
            return builder.ToString();
        }
        
        private static void ToArrayStringImpl(Array array, StringBuilder builder, long[] indexes, int dimension)
        {
            var length = array.GetLongLength(dimension);
            builder.Append('{');
            for (indexes[dimension] = 0; indexes[dimension] < length; indexes[dimension]++)
            {
                if (dimension == indexes.Length - 1)
                {
                    builder.Append(array.GetValue(indexes).ToValueString());
                } 
                else
                {
                    ToArrayStringImpl(array, builder, indexes, dimension + 1);
                }
                if (indexes[dimension] < array.GetLongLength(dimension) - 1)
                {
                    builder.Append(", ");
                }
            }
            builder.Append('}');
        }
                
        public static string ToTypeString(this Type type)
        {            
            var typeArgs = type.GetGenericArguments();
            return (typeArgs.Length > 0)
                ? type.Name.Split('`')[0] + '<' + string.Join(", ", Array.ConvertAll(typeArgs, typeArg => typeArg.ToTypeString())) + '>'
                : type.Name;
        }       
        
        public static string ToSafeTypeString(this object obj)
        {
            return (obj != null) ? obj.GetType().ToTypeString() : NullString;
        }
        
        public static Type GetSafeType(this object obj)
        {
            return (obj != null) ? obj.GetType() : null;
        }
               
    }
}